
;%include "src/descriptor.inc"
;org 0100h

org 07c00h

jmp short start
nop

%include "src/fat12hdr.asm"


start:
  mov ax, cs
  mov ds, ax
  mov es, ax
  mov ss, ax
  mov sp, 07c00h

  ; clear screen
  mov ax, 0600h   ; AH=6, AL=0h
  mov bx, 0700h   ; BL=07h
  mov cx, 0       ; (0, 0)
  mov dx, 0184fh  ; (80, 50)
  int 10h

  ; floppy reset
  xor ah, ah
  xor dl, dl
  int 13h

  ; Search osloader.bin in floppy 
  mov word [wSectorNo], SectorNoOfRootDir  

LABEL_SEARCH_IN_ROOT_DIR_BEGIN:
  cmp word [wRootDirSizeForLoop], 0
  jz LABEL_NO_LOADERBIN             ; read completed
  dec word [wRootDirSizeForLoop]    ; not found loader.bin if read completed
  
  mov ax, BaseOfLoader
  mov es, ax                        ; es <- BaseOfLoader
  mov bx, OffsetOfLoader            ; bx <- OffsetOfLoader es:bx = BaseOfLoader:OffsetOfLoader
  mov ax, [wSectorNo]               ; ax <- Sector No Of Root Dir
  mov cl, 1
  call ReadSector



  mov si, LoaderFileName            ; ds:si -> "loader.bin"
  mov di, OffsetOfLoader            ; es:di -> BaseOfLoader: 0100 = BaseOfLoader
  cld
  mov dx, 10h

LABEL_SEARCH_FOR_LOADERBIN:
  cmp dx, 0                 ; loop count
  jz LABEL_GOTO_NEXT_SECTOR_IN_ROOT_DIR   ; if read one sector completed then goto read next sector
  dec dx
  mov cx, 11
LABEL_CMP_FILENAME:
  cmp cx, 0
  jz LABEL_FILENAME_FOUND  ; if the 11 bytes is same as loader.bin the found the file
  dec cx
  lodsb                    ; ds:si -> al
  cmp al, byte [es:di]
  jz LABEL_GO_ON
  jmp LABEL_DIFFERENT       ; byte not equal indicate the DirectorEntry is not loader.bin
LABEL_GO_ON:
  inc di
  jmp LABEL_CMP_FILENAME
LABEL_DIFFERENT:
  and di, 0FFE0h
  add di, 20h
  mov si, LoaderFileName
  jmp LABEL_SEARCH_FOR_LOADERBIN
LABEL_GOTO_NEXT_SECTOR_IN_ROOT_DIR:
  add word [wSectorNo], 1
  jmp LABEL_SEARCH_IN_ROOT_DIR_BEGIN

LABEL_NO_LOADERBIN:
  mov dh, 2
  call PrintMessage
  jmp $

LABEL_FILENAME_FOUND:

  mov ax, RootDirSectors
  ;and di, 0FFE0h              ; di -> current item start
  and di, 0FFE0h              ; di -> current item start
  add di, 01Ah                ; di -> first sector
  mov cx, word [es:di]
  push cx                     ; save current sector no in FAT
  add cx, ax
  add cx, DeltaSectorNo       ; cl -> file loader.bin sector no 
  mov ax, BaseOfLoader
  mov es, ax                  ; es <- BaseOfLoader
  mov bx, OffsetOfLoader      ; bx <- OffsetOfLoader  es:bx = BaseOfLoader:OffsetOfLoader
  mov ax, cx     ;ax<- Sector no

LABEL_GOON_LOADING_FILE:
  push ax
  push bx
  mov ah, 0Eh
  mov al, '.'
  mov bl, 0Fh
  int 10h
  pop bx
  pop ax

  mov cl, 1
  call ReadSector

  pop ax           ; get sector no in FAT
  call GetFATEntry
  cmp ax, 0FFFh
  jz LABEL_FILE_LOADED
  push ax          ; save sector no in FAT
  mov dx, RootDirSectors
  add ax, dx
  add ax, DeltaSectorNo
  add bx, [BPB_SectorBytes]
  jmp LABEL_GOON_LOADING_FILE

LABEL_FILE_LOADED:
  mov dh, 1    ; "Ready."
  call PrintMessage ; show message

  ; goto jmp
  jmp BaseOfLoader:OffsetOfLoader   ; start execute loader.bin




; variable
BaseOfLoader      equ 09000h  ; loader.bin segment base address
OffsetOfLoader    equ 0100h   ; loader.bin segment offset

RootDirSectors    equ 0eh  ; number of Root Dir sectors
SectorNoOfRootDir equ 13h  ; first sector no of Root Dir
SectorNoOfFAT1    equ 01h  ; FAT1
DeltaSectorNo     equ 17   ; = BPB_RsvdSecCount + (BPB_NumberFATs*BPB_FATSz16) - 2 
wRootDirSizeForLoop  dw RootDirSectors ; Loop RootDir 
wSectorNo dw 0  ; sector NO for read
bOdd      db 0


; String
LoaderFileName    db "LOADER  BIN ", 0   ; loader.bin filename FILENAME must caps

MessageLength     equ 9
BootMessage:  db "Booting  "
Message1      db "Ready.   "
Message2      db "No loader"
Message3      db "Try Once."

; PrintMessage
PrintMessage:
  push bp
  push ax
  push bx
  push cx
  push dx
  mov ax, MessageLength
  mul dh
  add ax, BootMessage
  mov bp, ax
  mov ax, ds               ; ES:BP = string address
  mov es, ax
  mov cx, MessageLength
  mov ax, 01301h
  mov bx, 0007h
  mov dl, 0
  int 10h

  pop dx
  pop cx
  pop bx
  pop ax
  pop bp 
  ret

;ReadSector
;begin from  ax sector, read cl sector into es:bx
ReadSector:
  ; sector no -> c h s
  ; cylinder = y >> 1
  ; x % y
  ;--------------------- => heads = y & 1
  ; BPB_TrackSectors 
  ;                      rest z => start sector no = z+1
  ;
  push bp
  mov bp, sp
  sub esp, 2            ; 2 byte : sector number byte[bp-2]
 

  mov byte [bp-2], cl
  push bx               ; save bx
  mov bl, [BPB_TrackSectors]
  div bl                ; y == al,  z == ah
  inc ah                ; z++
  mov cl, ah            ; cl <- start sector no
  mov dh, al            ; dh <- y
  shr al, 1             ; y >> 1 (y/BPB_NumberHeads, BPB_NumberHeads = 2)
  mov ch, al            ; ch <- cylinder no
  and dh, 1             ; dh & 1 = heads no
  pop bx                ; restore bx
  ; get cylinder no, start sector no, heads no 
  mov dl, [BS_DriverNo]



.GoOnReading:
  mov ah, 2             ; read
  mov al, byte [bp - 2] ; read al sectors 
  int 13h
  jc .GoOnReading       ; if CF is set to 1 when error occured, read it repeatly until ok
  add esp, 2
  pop bp

  ret

; function GetFATEntry
GetFATEntry:
  push es
  push bx
  push ax
  mov ax, BaseOfLoader
  sub ax, 0100h        ; leave 4k after BaseOfLoader to store FAT
  mov es, ax
  pop ax
  mov byte [bOdd], 0
  mov bx, 3
  mul bx              ; dx:ax = ax * 3
  mov bx, 2
  div bx              ; dx:ax /2 ==> ax <- %, dx <- rest 
  cmp dx, 0
  jz LABEL_EVEN
  mov byte [bOdd], 1
LABEL_EVEN: 
  xor dx, dx
  mov bx, [BPB_SectorBytes]
  div bx
  push dx
  mov bx, 0
  add ax, SectorNoOfFAT1
  mov cl, 2
  call ReadSector
  pop dx
  add bx, dx
  mov ax, [es:bx]
  cmp byte [bOdd], 1
  jnz LABEL_EVEN_2
  shr ax, 4
LABEL_EVEN_2:
  and ax, 0FFFh

LABEL_GET_FAT_ENTRY_OK:
  pop bx
  pop es
  ret

times 510-($-$$)  db 0   ; fill the rest space with 512 bytes
dw    0xaa55             ; end flag

